﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Collections.Concurrent;


namespace C0710_ChatRoom_Server
{
    /// <summary>
    /// 与客户端的连接通信类
    /// </summary>
    public class ConnectionClient
    {
        Socket sokMsg;
        DGShowMsg dgShowMsg;            //负责向主窗体文本框显示消息的方法委托
        DGShowMsg dgRemoveConnection;   // 负责从主窗体中移除当前连接
        Thread threadMsg;
        Dictionary<string, ConnectionClient> dictConn;
        ConcurrentDictionary<string, ConnectionClient> dictClient;
        DateTime timestamp;             //第一次连接的时间
        string clientId;
        //bool isRec = true;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sokMsg">通信套接字</param>
        /// <param name="dgShowMsg">向主窗体文本框显示消息的方法委托</param>
        public ConnectionClient(Socket sokMsg, Dictionary<string, ConnectionClient> _dictConn, ConcurrentDictionary<string, ConnectionClient> _dictClient, DGShowMsg dgShowMsg, DGShowMsg dgRemoveConnection)
        {
            this.dictConn = _dictConn;
            this.dictClient = _dictClient;
            this.sokMsg = sokMsg;
            this.dgShowMsg = dgShowMsg;
            this.dgRemoveConnection = dgRemoveConnection;
            this.timestamp = DateTime.Now;
            this.threadMsg = new Thread(RecMsg);
            this.threadMsg.IsBackground = true;
            this.threadMsg.Start();
        }

        /// <summary>
        /// 向特定客户端转发消息
        /// </summary>
        /// <param name="strMsg"></param>
        public void SendTo(string strMsg)
        {
            try
            {
                var msgArr = strMsg.Split('|');
                if (msgArr.Length <= 1)
                    return;

                string clientId = Convert.ToInt32(msgArr[0].Trim()).ToString("x8").ToUpper().Substring(4, 4);
                dgShowMsg("给设备 " + clientId + " 发送消息");
                Log4NetInfo.Info("给设备 " + clientId + " 发送消息");

                if (!this.dictClient.ContainsKey(clientId))
                {
                    Log4NetInfo.Info("no client to send");
                    return;
                }
                var sock = this.dictClient[clientId];

                strMsg = "O1O\r\n";
                byte[] arrMsg = System.Text.Encoding.ASCII.GetBytes(strMsg);
                sock.sokMsg.Send(arrMsg);
                dgShowMsg("给客户端" + sock.sokMsg.RemoteEndPoint + "发送[开启]命令");
                foreach (var item in dictClient)
                {
                    IPEndPoint clientipe = (IPEndPoint)item.Value.sokMsg.RemoteEndPoint;
                    dgShowMsg("有效客户端IP:" + clientipe);
                }

                Thread.Sleep(2000);

                string strMsg1 = "ANC\r\n";
                byte[] arrMsg1 = System.Text.Encoding.ASCII.GetBytes(strMsg1);
                sock.sokMsg.Send(arrMsg1);                
                dgShowMsg("给客户端" + sock.sokMsg.RemoteEndPoint + "发送[关闭]命令");
                Log4NetInfo.Info("消息发送完毕! 客户端:" + clientId);
            }
            catch (Exception ex)
            {
                Log4NetInfo.Info("SendTo is Error: " + ex.Message);
            }
        }
        /// <summary>
        /// 销毁客户端资源
        /// </summary>
        /// <param name="sock"></param>
        //private void DestroySocket(Socket sock)
        //{
        //    dgShowMsg("客户端 " + sock.RemoteEndPoint + " 断开");
        //    Log4NetInfo.Info("客户端 " + sock.RemoteEndPoint + " 断开");
        //    if (sock.Connected)
        //    {
        //        sock.Shutdown(SocketShutdown.Both);
        //    }
        //    sock.Close();
        //}

        /// <summary>
        /// 监听客户端发送来的消息
        /// </summary>
        void RecMsg()
        {
            while (true)
            {
                try
                {
                    byte[] arrMsg = new byte[1024 * 1024 * 2];
                    int length = sokMsg.Receive(arrMsg);
                    if (length <= 0)
                    {
                        sokMsg.Shutdown(SocketShutdown.Both);
                        sokMsg.Close();
                        break;
                    }
                    //接收对应客户端发来的消息，将接收到的消息数组里真实消息转成字符串                    
                    string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, length) + "\r\n";
                    dgShowMsg(strMsg);
                    if (!string.IsNullOrEmpty(strMsg))
                    {
                        if (strMsg.Split(':').Length <= 1)
                            SendTo(strMsg);
                        else
                            AddClientDict(strMsg);
                    }
                }
                catch (SocketException cex)
                {
                    //isRec = false;
                    //Log4NetInfo.Info("RecMsg errorMsg:" + ex.Message);

                    //if (!string.IsNullOrEmpty(this.clientId) && this.dictClient.ContainsKey(this.clientId))
                    //{
                    //    ConnectionClient cc;
                    //    dictClient.TryRemove(this.clientId, out cc);
                    //    Log4NetInfo.Info(this.clientId + "设备已断开连接\r\n");
                    //}
                    if (cex.ErrorCode == 10054)
                    {
                        //client.ClientSocket.Shutdown(SocketShutdown.Both);
                        //client.ClientSocket.Close();
                        break;
                    }
                }
                //DestroySocket(sokMsg);
            }
        }

        /// <summary>
        /// 将设备IP加入字典
        /// </summary>
        /// <param name="msg"></param>
        public void AddClientDict(string msg)
        {
            var idArr = msg.Split(':');
            IPEndPoint clientipe = (IPEndPoint)sokMsg.RemoteEndPoint;
            string ip = clientipe.Address.ToString();
            //string port = clientipe.Port.ToString();
            var serverIP = System.Configuration.ConfigurationManager.AppSettings["serverIp"];
            if (ip != serverIP && idArr.Length > 1)
            {
                var currClientId = idArr[1].Trim();//设备心跳数据格式 ID:0005

                if (!this.dictClient.ContainsKey(currClientId))
                {
                    var addRel = dictClient.TryAdd(currClientId, this);//第一次连接，添加到字典
                    if (addRel)
                        Log4NetInfo.Info("首次加载客户端" + currClientId + "成功.");
                    else
                        Log4NetInfo.Info("首次加载客户端" + currClientId + "失败.");
                    this.clientId = currClientId;
                }
                else if (!dictClient[currClientId].sokMsg.Connected)
                {
                    ConnectionClient cc;
                    dictClient.TryRemove(currClientId, out cc);
                    var addRel = dictClient.TryAdd(currClientId, this);//第N次连接，添加到字典
                    this.clientId = currClientId;
                }
                else
                {
                    if (dictClient[currClientId].sokMsg.Send(Encoding.ASCII.GetBytes("\r\n")) <= 0)
                    {
                        dictClient[currClientId].sokMsg.Shutdown(SocketShutdown.Both);
                        dictClient[currClientId].sokMsg.Close();
                    }

                    ConnectionClient cc;
                    dictClient.TryRemove(currClientId, out cc);
                    var addRel = dictClient.TryAdd(currClientId, this);//第N次连接，添加到字典
                    this.clientId = currClientId;
                }
            }
        }

        /// <summary>
        /// 关闭与客户端连接
        /// </summary>
        //public void CloseConnection()
        //{
        //    isRec = false;
        //}
    }
}
